package cur.nature.starter.common.idgenerator.mirco;

import cur.nature.framework.core.log.LOG;
import cur.nature.framework.core.mirco.MircoIdUtil;
import cur.nature.framework.core.util.DateUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;

import java.net.Inet4Address;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

//@Configuration
public class MircoIdConfig {

    @Value("${server.port}")
    private int port;
    @Value("${spring.application.name}")
    private String serverName;
    @Autowired
    private MircoServerDao mircoServerDao;
    private Admin_MircoServerVO mircoServerVO;

    @PostConstruct
    public void init() throws Exception {
        this.mircoServerVO = getMircoServer(0, 15);
        final  Long workerId = Long.valueOf(mircoServerVO.getServerSeq());
        LOG.info("workerId:{}", workerId);
        // 初始化snowflake, 有序
        new MircoIdUtil(workerId, 1738589989639L,4L,12L);
    }

    @PreDestroy
    public void destroy() {
        try {
            // 删除数据
            mircoServerVO.setOperateType(3);
            int rows = mircoServerDao.save(mircoServerVO);
            LOG.info("id config destory :{}", rows);
        } catch (Exception e) {
            LOG.error("", e);
        }
    }

    /**
     * 每隔一小时, 更新一次当前记录的时间
     */
//    @Scheduled(cron = "0 0 */1 * * *")
    @Scheduled(cron = "0 */1 * * * *")
    public void update() {
        try {
            // 删除数据
            mircoServerVO.setOperateType(2);
            int rows = mircoServerDao.save(mircoServerVO);
            LOG.info("id config update :{}", rows);
        } catch (Exception e) {
            LOG.error("", e);
        }
    }

    /**
     * 每隔三小时,扫描一次,删除超过三小时都没有更新过的记录
     */
//    @Scheduled(cron = "0 0 */3 * * *")
    @Scheduled(cron = "0 */3 * * * *")
    public void clear() {
        LOG.info("id config clear start", 0);
        try {
            // 找出所有的mirco server
            final Admin_MircoServerVO.query_Param param = new Admin_MircoServerVO.query_Param();
            param.setServerName(serverName);
            List<Admin_MircoServerVO> list = mircoServerDao.query(param);
            List<Admin_MircoServerVO> deleteList = new ArrayList<>();
            if (list != null && !list.isEmpty()) {
                // 找出更新时间超过三个小时的记录
                final LocalDateTime now = LocalDateTime.now();
                for (Admin_MircoServerVO vo : list) {
                    LocalDateTime updateTime = DateUtil.toLocalDateTime(vo.getModifyDate());
                    Duration duration = DateUtil.compare(updateTime, now);
                    long hours = duration.toHours();
                    if (hours > 3) {
                        deleteList.add(vo);
                    }
                }

                // 删除
                if (!deleteList.isEmpty()) {
                    List<Long> ids = deleteList.stream().map(Admin_MircoServerVO::getId).toList();
                    int rows = mircoServerDao.deleteByIdList(ids);
                    LOG.info("id config clear :{}", rows);
                }
            }
        } catch (Exception e) {
            LOG.error("", e);
        }
    }

    private Admin_MircoServerVO getMircoServer(int seq, final int cycles) throws Exception {
        try {
            // 找出最小的可用 seq
            final Admin_MircoServerVO.query_Param param = new Admin_MircoServerVO.query_Param();
            param.setServerName(serverName);
            List<Admin_MircoServerVO> list = mircoServerDao.query(param);
            if (list != null && list.size() > 0) {
                int finalSeq = seq;
                Optional<Admin_MircoServerVO> optional = list.stream().filter(s -> s.getServerSeq() == finalSeq).findFirst();
                if (optional.isPresent()) {
                    seq++;

                }
            }

            // 插入数据
            final Long id = MircoIdUtil.generateId();
            Admin_MircoServerVO vo = new Admin_MircoServerVO();
            vo.setId(id);
            vo.setServerSeq(seq);
            vo.setServerName(serverName);
            vo.setOperateType(1);
            vo.setIp(Inet4Address.getLocalHost().getHostAddress());
            vo.setPort(port);
            mircoServerDao.save(vo);
            return vo;
        } catch (Exception e) {
            seq++;
            LOG.info("update seq : " + seq+",msg:{}", e.getMessage());
            if (seq > cycles) { throw e; }
            return getMircoServer(seq, cycles);
        }
    }
}
